// ball_filteringobserver.h                                           -*-C++-*-
#ifndef INCLUDED_BALL_FILTERINGOBSERVER
#define INCLUDED_BALL_FILTERINGOBSERVER

#include <bsls_ident.h>
BSLS_IDENT("$Id: $")

//@PURPOSE: Provide an observer that filters log records.
//
//@CLASSES:
//  ball::FilteringObserver: observer that filters log records
//
//@SEE_ALSO: ball_record, ball_context, ball_loggermanager
//
//@DESCRIPTION: This component provides a concrete implementation of the
// 'ball::Observer' protocol for receiving and processing log records:
//..
//               ,-----------------------.
//              ( ball::FilteringObserver )
//               `-----------------------'
//                           |              ctor
//                           V
//                    ,--------------.
//                   ( ball::Observer )
//                    `--------------'
//                                          publish
//                                          dtor
//..
// 'ball::FilteringObserver' processes the log records it receives through its
// 'publish' method and conditionally forwards them to the inner observer
// supplied at construction.
//
///Usage
///-----
// This section illustrates intended use of this component.
//
///Example 1: Basic Usage
/// - - - - - - - - - - -
// This example shows how to use filtering observer to route some log records
// to a designated observer.  A common use case is routing all log records for
// a given category (or category pattern) to a separate log file.
//
// First, we create a filter that will match a log record's category against
// the pattern "EQUITY.*":
//..
//  bool categoryFilter(const ball::Record& record, const ball::Context&)
//  {
//      return ball::PatternUtil::isMatch(record.fixedFields().category(),
//                                        "EQUITY.*");
//  }
//..
// Then, we create the observer that will receive filtered log records and
// create a filtering observer:
//..
//  bsl::shared_ptr<ball::TestObserver> innerObserver(
//                                         new ball::TestObserver(&bsl::cout));
//
//  ball::FilteringObserver filteringObserver(innerObserver, categoryFilter);
//..
// Next, we issue a series of log records and verify that only records with the
// category matching the pattern are published to the inner observer:
//..
//  const ball::Context context(ball::Transmission::e_PASSTHROUGH, 0, 1);
//
//  ball::RecordAttributes fixedFields;
//
//  bsl::shared_ptr<ball::Record> record;
//  record.createInplace();
//
//  fixedFields.setCategory("CURNCY.USDGBP");
//  record->setFixedFields(fixedFields);
//  filteringObserver.publish(record, context);
//
//  assert(0 == innerObserver->numPublishedRecords());  // dropped
//
//  fixedFields.setCategory("EQUITY.NYSE");
//  record->setFixedFields(fixedFields);
//  filteringObserver.publish(record, context);
//
//  assert(1 == innerObserver->numPublishedRecords());  // forwarded
//
//  fixedFields.setCategory("EQUIT.");
//  record->setFixedFields(fixedFields);
//  filteringObserver.publish(record, context);
//
//  assert(1 == innerObserver->numPublishedRecords());  // dropped
//..

#include <balscm_version.h>

#include <ball_observer.h>

#include <bslma_allocator.h>
#include <bslma_stdallocator.h>
#include <bslma_usesbslmaallocator.h>

#include <bslmf_allocatorargt.h>
#include <bslmf_nestedtraitdeclaration.h>

#include <bsls_assert.h>
#include <bsls_review.h>

#include <bsl_functional.h>
#include <bsl_memory.h>

namespace BloombergLP {
namespace ball {

class Context;
class Record;

                           // =======================
                           // class FilteringObserver
                           // =======================

class FilteringObserver : public Observer {
    // This class provides a concrete implementation of the 'Observer' protocol
    // that filters the 'Record' and 'Context' objects passed to its 'publish'
    // method based on a callback (function or functor) supplied at
    // construction.  The callback must be convertible to:
    //..
    //  bsl::function<bool(const Record&, const Context&)>
    //..
    // If the callback returns 'true' for the 'Record' and 'Context', then they
    // are forwarded to the 'publish' method of an observer also supplied at
    // construction.  If the callback returns 'false', then the 'Record' and
    // 'Context' are ignored (i.e., they are filtered out by this observer).

  public:
    // PUBLIC TYPES
    typedef bsl::function<bool(const Record&, const Context&)>
                                                          RecordFilterCallback;
    // 'RecordFilterCallback' is the type of a user-supplied callback functor
    // used to filter the supplied 'Record' and 'Context' objects based on the
    // user-defined criteria provided by the functor.

  private:
    // DATA
    bsl::shared_ptr<Observer> d_innerObserver;  // inner observer
    RecordFilterCallback      d_recordFilter;   // record filter callback

    // NOT IMPLEMENTED
    FilteringObserver(const FilteringObserver&);
    FilteringObserver& operator=(const FilteringObserver&);

  public:
    // TRAITS
    BSLMF_NESTED_TRAIT_DECLARATION(FilteringObserver,
                                   bslma::UsesBslmaAllocator);

    // CREATORS
    FilteringObserver(const bsl::shared_ptr<Observer>&  observer,
                      const RecordFilterCallback&       recordFilterCallback,
                      bslma::Allocator                 *basicAllocator = 0);
        // Create a filtering observer that conditionally passes log records to
        // the specified 'observer' based on the specified
        // 'recordFilterCallback'.  Optionally specify a 'basicAllocator' used
        // to supply memory.  If 'basicAllocator' is 0, the currently installed
        // default allocator is used.  The behavior is undefined if 'observer'
        // is 0 or a cycle is created among observers.

    virtual ~FilteringObserver();
        // Destroy this filtering observer.

    // MANIPULATORS
    using Observer::publish;

    virtual void publish(const bsl::shared_ptr<const Record>& record,
                         const Context&                       context);
        // Process the specified log 'record' having the specified publishing
        // 'context'.  Forward 'record' and 'context' to the 'publish' method
        // of the observer supplied at construction if the filter callback
        // supplied at construction returns 'true' for 'record' and 'context',
        // and ignore (filter out) 'record' and 'context' otherwise.  The
        // behavior is undefined if 'record' or 'context' is modified during
        // the execution of this method.

    virtual void releaseRecords();
        // Discard any shared reference to a 'Record' object that was supplied
        // to the 'publish' method, and is held by this observer.  Note that
        // this operation should be called if resources underlying the
        // previously provided shared-pointers must be released.
};

// ============================================================================
//                              INLINE DEFINITIONS
// ============================================================================

                           // -----------------------
                           // class FilteringObserver
                           // -----------------------

// CREATORS
inline
FilteringObserver::FilteringObserver(
                        const bsl::shared_ptr<Observer>&  observer,
                        const RecordFilterCallback&       recordFilterCallback,
                        bslma::Allocator                 *basicAllocator)
: d_innerObserver(observer)
, d_recordFilter(bsl::allocator_arg_t(),
                 bsl::allocator<RecordFilterCallback>(basicAllocator),
                 recordFilterCallback)
{
    BSLS_ASSERT(observer);
}

// MANIPULATORS
inline
void FilteringObserver::releaseRecords()
{
}

}  // close package namespace
}  // close enterprise namespace

#endif

// ----------------------------------------------------------------------------
// Copyright 2017 Bloomberg Finance L.P.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ----------------------------- END-OF-FILE ----------------------------------
